﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using r2mp_DataStructures;

namespace r2mp_GUI
{
    public partial class MTAWorker : r2mp_DataStructures.DiagramWorker
    {
        private int error = 0;
        private Brush[] colors = { Brushes.Red, Brushes.Orange, Brushes.DarkOrchid, Brushes.LightGreen, 
                                       Brushes.Green, Brushes.Teal, Brushes.LightBlue, Brushes.Blue, 
                                       Brushes.Violet, Brushes.Black };
        private int index = 0;
        private int text = 0;
        private MTA mta = null;
        private DateTime first = DateTime.MinValue;
        private DateTime last = DateTime.MinValue;
        private int dateCount = 0;
        private float legend = -1;
        private int drawn = 0;
        private List<MTAWrapper> milestones = new List<MTAWrapper>();
        private Font font;
        private Pen pen;
        private Panel panel;
        private List<String> errors = new List<string>();
        private bool errorShown = false;

        public MTAWorker(MTA mta, Panel panel)
        {
            this.panel = panel;
            this.mta = mta;
            GlobalConfig.Periode = mta.Periode;
            setDates();
            countDate();
            prepareMilestones();
            if (mta.Periode == MTA.Month)
            {
                first = first.AddDays(-(first.Day - 1));
            }
            else
            {
                switch (first.DayOfWeek)
                {
                    case DayOfWeek.Tuesday:
                        first = first.AddDays(-1);
                        break;
                    case DayOfWeek.Wednesday:
                        first = first.AddDays(-2);
                        break;
                    case DayOfWeek.Thursday:
                        first = first.AddDays(-3);
                        break;
                    case DayOfWeek.Friday:
                        first = first.AddDays(-4);
                        break;
                    case DayOfWeek.Saturday:
                        first = first.AddDays(-5);
                        break;
                    case DayOfWeek.Sunday:
                        first = first.AddDays(-6);
                        break;
                }
            }
            SetLegend();
            secondCheck();
            Scale();
        }

        private void SetLegend()
        {
            legend = -1;
            foreach (MTAWrapper now in milestones)
            {
                if (legend == -1)
                {
                    legend = TextRenderer.MeasureText(now.Item.Name, font).Width;
                }
                else if (TextRenderer.MeasureText(now.Item.Name, font).Width > legend)
                {
                    legend = TextRenderer.MeasureText(now.Item.Name, font).Width;
                }
            }
        }

        private void secondCheck()
        {
            int temp;
            List<MTAWrapper> remove = new List<MTAWrapper>();
            foreach (MTAWrapper now in milestones)
            {
                temp = now.Id;
                foreach (int timeshift in now.Item.Timeshifts)
                {
                    temp += timeshift;
                }


                if (temp < 1)
                {
                    error = 1;
                    errors.Add(now.Item.Name);
                    remove.Add(now);
                }
                else if (temp > dateCount)
                {
                    dateCount = temp;
                }
            }
            if (error != 0)
            {
                foreach (MTAWrapper now in remove)
                {
                    milestones.Remove(now);
                }
            }
        }

        private void prepareMilestones()
        {
            DateTime temp;
            int count;
            foreach (Milestone now in mta.Milestones)
            {
                temp = first;
                count = 0;
                while (temp.Date <= now.PlannedCompletionDate.Date)
                {
                    if (GlobalConfig.Periode == MTA.Month)
                    {
                        temp = temp.AddMonths(1);
                    }
                    else
                    {
                        temp = temp.AddDays(7);
                    }
                    count++;
                }
                milestones.Add(new MTAWrapper(count, now, colors[index]));
                index++;
                index = index % 10;
            }
        }

        public void Scale()
        {
            int length = 50;
            text = (int)(TextRenderer.MeasureText(first.ToShortDateString(), font).Width + 5 * GlobalConfig.Scale);
            SetLegend();
            GlobalConfig.Width = length * GlobalConfig.Scale;
            font = new Font(Form.DefaultFont.FontFamily, GlobalConfig.Width / 4);
            if (drawn == 1)
            {
                if (error != 0 && !errorShown)
                {
                    for (int i = 0; i < errors.Count; i++)
                    {
                        MessageBox.Show("Der Meilensteint " + errors[i] + "enthält ungültige Daten!\n"
                            + "(Ein Fertigstellungsdatum in der Vergangenheit)", "Achtung!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                    error = 0;
                    errorShown = true;
                }
                drawn = 2;
            }
        }

        private void countDate()
        {
            DateTime temp = first;
            while ((temp.Date <= last.Date))
            {
                if (GlobalConfig.Periode == MTA.Month)
                {
                    dateCount++;
                    temp = temp.AddMonths(1);
                }
                else
                {
                    dateCount++;
                    temp = temp.AddDays(7);
                }
            }
        }

        private void setDates()
        {
            foreach (Milestone now in mta.Milestones)
            {
                if (first == DateTime.MinValue)
                {
                    first = now.PlannedCompletionDate;
                    last = now.PlannedCompletionDate;
                }
                if (now.PlannedCompletionDate < first)
                {
                    first = now.PlannedCompletionDate;
                }
                else if (now.PlannedCompletionDate > last)
                {
                    last = now.PlannedCompletionDate;
                }
            }
        }


        public void draw(Graphics g)
        {
            if (legend > -1)
            {
                Scale();
                int nextVal;
                panel.Height = (int)(text + GlobalConfig.Width * dateCount);
                panel.Width = (int)(legend * 2 + GlobalConfig.Width * dateCount + 30 * GlobalConfig.Scale);
                if (text + font.Height * milestones.Count > panel.Height)
                {
                    panel.Height = text + font.Height * milestones.Count;
                }
                PointF start = new PointF(0 + legend, 0 + text);
                PointF begin;
                PointF end;

                for (int i = dateCount; i > 0; i--)
                {
                    begin = new PointF(start.X + (dateCount - i) * GlobalConfig.Width, start.Y);
                    end = new PointF(start.X + (dateCount - i) * GlobalConfig.Width, start.Y + (i * GlobalConfig.Width));
                    g.DrawLine(Pens.Black, begin, end);
                    begin = new PointF(start.X, start.Y + ((dateCount - i) * GlobalConfig.Width));
                    end = new PointF(start.X + i * GlobalConfig.Width, start.Y + ((dateCount - i) * GlobalConfig.Width));
                    g.DrawLine(Pens.Black, begin, end);
                }
                begin = new PointF(start.X + dateCount * GlobalConfig.Width, start.Y);
                end = new PointF(start.X, start.Y + dateCount * GlobalConfig.Width);
                g.DrawLine(Pens.Black, begin, end);

                StringFormat sf = new StringFormat();
                sf.FormatFlags = StringFormatFlags.DirectionVertical;
                for (int i = 0; i < dateCount; i++)
                {
                    if (mta.Periode == MTA.Month)
                    {
                        float startx = i * GlobalConfig.Width + legend + TextRenderer.MeasureText(first.AddMonths(i).ToShortDateString(), font).Height / 2;
                        g.DrawString(first.AddMonths(i).ToShortDateString(), font, Brushes.Black, startx, 0, sf);
                    }
                    else
                    {
                        float startx = i * GlobalConfig.Width + legend + TextRenderer.MeasureText(first.AddDays(7 * i).ToShortDateString(), font).Height / 2;
                        g.DrawString(first.AddDays(i * 7).ToShortDateString(), font, Brushes.Black, startx, 0, sf);
                    }
                }

                List<PointF> points;
                int ind = 0;
                foreach (MTAWrapper now in milestones)
                {
                    points = new List<PointF>();
                    // Legende!

                    int count = dateCount - now.Id;
                    float y = count * GlobalConfig.Width + text;
                    float x = GlobalConfig.Width / 2 + legend;
                    y += GlobalConfig.Width / 2;

                    float TextY = y - TextRenderer.MeasureText(now.Item.Name, font).Height / 2;

                    //----------------------------

                    PointF temp = new PointF(x, y);
                    points.Add(temp);

                    nextVal = now.Id;
                    float tempx = x;
                    float tempy = y;
                    for (int i = 0; i < nextVal && i < now.Item.Timeshifts.Count /*&& i + now.Id - 1 < nextVal + now.Item.Timeshifts[i]*/; i++)
                    {
                        if (now.Item.Timeshifts[i] != 0 && i + 1 >= nextVal + now.Item.Timeshifts[i])
                        {
                            error = 1;
                            if (!errors.Contains(now.Item.Name))
                            {
                                errors.Add(now.Item.Name);
                            }
                            points = null;
                            break;
                        }
                        else if (!(now.Item.Timeshifts[i] == 0 && i + 1 == nextVal))
                        {
                            tempx += GlobalConfig.Width;
                            tempy -= GlobalConfig.Width * now.Item.Timeshifts[i];
                            temp = new PointF(tempx, tempy);
                            points.Add(temp);

                            nextVal += now.Item.Timeshifts[i];
                        }
                    }


                    if (points != null)
                    {
                        g.DrawString(now.Item.Name, font, Brushes.Black, 0, TextY);
                        pen = new Pen(now.Color, GlobalConfig.Width / 20);
                        if (points.Count > 1)
                        {
                            

                            g.DrawLines(pen, points.ToArray());
                        }
                        float rectWidth = GlobalConfig.Width / 12;
                        foreach (PointF rec in points)
                        {
                            g.FillRectangle(now.Color, rec.X - rectWidth, rec.Y - rectWidth, rectWidth * 2, rectWidth * 2);
                        }

                        temp = new PointF(panel.Width - (30 * GlobalConfig.Scale) - legend, text + ind * font.Height);
                        g.DrawLine(pen, temp.X, temp.Y + font.Height / 2, temp.X + (25 * GlobalConfig.Scale), temp.Y + font.Height / 2);
                        g.DrawString(now.Item.Name, font, Brushes.Black, temp.X + (30 * GlobalConfig.Scale), temp.Y);
                        ind++;
                    }
                }
            }
            if (drawn == 0)
            {
                drawn = 1;
            }
        }

        private class MTAWrapper
        {
            private int id;

            public int Id
            {
                get { return id; }
                set { id = value; }
            }
            private Milestone item;

            public Milestone Item
            {
                get { return item; }
                set { item = value; }
            }
            private Brush col;

            public Brush Color
            {
                get { return col; }
                set { col = value; }
            }

            public MTAWrapper()
            {

            }

            public MTAWrapper(int id, Milestone item, Brush col)
            {
                this.id = id;
                this.item = item;
                this.col = col;
            }
        }



        public void zoomIn()
        {
            GlobalConfig.Scale += 0.05f;
            Scale();
        }

        public void zoomOut()
        {
            if (GlobalConfig.Scale - 0.05f > 0.2f)
            {
                GlobalConfig.Scale -= 0.05f;
                Scale();
            }
        }

        public Panel DrawingPanel
        {
            set { panel = value; }
        }
    }
}